// /////////////////////////////////////////////////////////////////////////////
//
// Name:            HeightmapProcessor.cpp
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           AssetProcessor for processing heightmaps in an AssetGroup.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

// Include files
#include "HeightmapProcessor.h"
#include "../core/GameManager.h"


// HeightmapProcessor class
// HeightmapProcessor constructor.
HeightmapProcessor::HeightmapProcessor(AssetGroup *parent)
: AssetProcessor(parent, "heightmaps"), mIsReloading(false)
{
}

// HeightmapProcessor deconstructor.
HeightmapProcessor::~HeightmapProcessor()
{
    removeAssets();
}

// Gets the heightmap with the given filename.
IReadFile* HeightmapProcessor::getHeightMap(const std::string &fileName)
{
#ifdef WIN32
	std::string tmp = fileName;
	std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
    std::map<std::string, std::pair<c8*, long> >::iterator it = mHeightMaps.find(tmp);
#else
    std::map<std::string, std::pair<c8*, long> >::iterator it = mHeightMaps.find(fileName);
#endif

    if(it != mHeightMaps.end())
    {
       c8 *fBuffer = (it->second).first;
       s32 fSize = static_cast<s32>((it->second).second);

       IReadFile *file = GameManager::Instance()->getDevice()->getFileSystem()
                           ->createMemoryReadFile(fBuffer, fSize, fileName.c_str());
       return file;
    }

    return NULL;
}

// Loads the mesh with the given filename.
bool HeightmapProcessor::loadAsset(const std::string &fileName)
{
    // Retrieve pointers to sub-sytems of the Irrlicht engine.
    IFileSystem *fileSystem = GameManager::Instance()->getDevice()->getFileSystem();

    // Change the working directory to the heightmap directory.
    std::string workingDir = (fileSystem->getWorkingDirectory()).c_str();

    if(!fileSystem->changeWorkingDirectoryTo( (pParent->getBaseDir()).c_str() ) )
      return false;

    if(!fileSystem->changeWorkingDirectoryTo("./heightmaps/"))
      return false;

    // Load the heightmap.
    IReadFile *file = fileSystem->createAndOpenFile(fileName.c_str());

    if(file)
    {
       // Retrieve data.
       long fSize = file->getSize();
       c8 *fBuffer = new c8[fSize+1];
       memset(fBuffer, 0, fSize+1);

       file->read(fBuffer, fSize);
       file->drop();

       // Store data.
       mHeightMaps[fileName] = std::pair<c8*, long>(fBuffer, fSize);
       cout << "Loaded heightmap: " << fileName << "\n";

       // Handle events.
       if(mIsReloading)
       {
          IReadFile *heightMap = fileSystem->createMemoryReadFile(fBuffer, static_cast<s32>(fSize),
                                                             fileName.c_str());
          pParent->emitEvent(std::string("heightmaps/") + fileName, heightMap);
       }

       else
         pParent->createEventSlot(std::string("heightmaps/") + fileName);
    }

    // Clean up.
    fileSystem->changeWorkingDirectoryTo(workingDir.c_str());

    return (file) ? true : false;
}

// Loads the meshes associated with this asset group.
void HeightmapProcessor::loadAssets()
{
    // Retrieve pointers to sub-sytems of the Irrlicht engine.
    IFileSystem *fileSystem = GameManager::Instance()->getDevice()->getFileSystem();

    // Change the working directory to the heightmaps directory.
    std::string workingDir = (fileSystem->getWorkingDirectory()).c_str();

    if(!fileSystem->changeWorkingDirectoryTo( (pParent->getBaseDir()).c_str() ) )
      return;

    if(!fileSystem->changeWorkingDirectoryTo("./heightmaps/"))
      return;

    // Read the heightmaps.
    IFileList *fileList = fileSystem->createFileList();

    for(u32 i = 0; i < fileList->getFileCount(); i++)
    {
        // Get file name.
        std::string fileName = (fileList->getFileName(i)).c_str();

        if(fileName == "..")
          continue;

        // Load the heightmap.
        IReadFile *file = fileSystem->createAndOpenFile(fileName.c_str());

        if(file)
        {
           // Retrieve data.
           long fSize = file->getSize();
           c8 *fBuffer = new c8[fSize+1];
           memset(fBuffer, 0, fSize+1);

           file->read(fBuffer, fSize);
           file->drop();

           // Store data.
           mHeightMaps[fileName] = std::pair<c8*, long>(fBuffer, fSize);
           cout << "Loaded heightmap: " << fileName << "\n";

           // Handle events.
           if(mIsReloading)
           {
              IReadFile *heightMap = fileSystem->createMemoryReadFile(fBuffer, static_cast<s32>(fSize),
                                                             fileName.c_str());
              pParent->emitEvent(std::string("heightmaps/") + fileName, heightMap);
           }

           else
             pParent->createEventSlot(std::string("heightmaps/") + fileName);
        }
    }

    // Clean up.
    fileList->drop();

    fileSystem->changeWorkingDirectoryTo(workingDir.c_str());
}

// Reloads the asset with the given filename.
bool HeightmapProcessor::reloadAsset(const std::string &fileName)
{
    mIsReloading = true;

    removeAsset(fileName);
    bool succeeded = loadAsset(fileName);

    mIsReloading = false;

    return succeeded;
}

// Reloads all assets.
void HeightmapProcessor::reloadAssets()
{
    mIsReloading = true;

    removeAssets();
    loadAssets();

    mIsReloading = false;
}

// Removes the asset with the given filename.
bool HeightmapProcessor::removeAsset(const std::string &fileName)
{
    // Try to find the given heightmap.
#ifdef WIN32
	std::string tmp = fileName;
	std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
    std::map<std::string, std::pair<c8*, long> >::iterator it = mHeightMaps.find(tmp);
#else
    std::map<std::string, std::pair<c8*, long> >::iterator it = mHeightMaps.find(fileName);
#endif

    // Did we find the heightmap?
    if(it != mHeightMaps.end())
    {
       // Handle events.
       if(!mIsReloading)
       {
          std::string slotName = std::string("heightmaps/") + it->first;

          pParent->emitEvent(slotName, NULL);
          pParent->removeEventSlot(slotName);
       }

       // Delete the heightmap.
       c8 *fBuffer = (it->second).first;
       delete [] fBuffer;
       mHeightMaps.erase(it);

       return true;
    }

    // We didn't find the heightmap.
    else return false;
}

// Removes all asssets.
void HeightmapProcessor::removeAssets()
{
    // Delete the heightmaps.
    std::map<std::string, std::pair<c8*, long> >::iterator it;

    for(it = mHeightMaps.begin(); it != mHeightMaps.end(); it++)
    {
       // Handle events.
       if(!mIsReloading)
       {
          std::string slotName = std::string("heightmaps/") + it->first;

          pParent->emitEvent(slotName, NULL);
          pParent->removeEventSlot(slotName);
       }

       // Delete the heightmap.
       c8 *fBuffer = (it->second).first;
       delete [] fBuffer;
    }

    // Clear the heightmaps map.
    mHeightMaps.clear();
}

// Creates a new HeightmapProcessor.
AssetProcessor* HeightmapProcessor::createProcessor(AssetGroup *parent)
{
    return new HeightmapProcessor(parent);
}

// End of File
